מכירים את המילים בשיר "מה נעשה, מה נע-עשה עם אתר מלא שגיאות כזה"? זה הגרסה של המשתמש המתוסכל כשהוא נכנס וכל מיני notice צצים בכל הכיוונים, ו-warningים חוגגים להם. בכאלה טיפלנו במדריך הקודם. אבל מה עם שגיאות קריטיות, כמו E_PARSE, E_ERROR ו-out of memory?
שגיאות כדאי לתפוס. שגיאות קריטיות כדאי עוד יותר, כי במקרה של שגיאה קריטית המשתמש לא יראה עמוד יפה ובקשת סליחה על התקלה, אלא הודעות שגיאה טכנית עם מידע על שורות, קבצים ופונקציות פנימיות - זה בטוח לא מה שאנחנו רוצים שהשתמש יראה.
ב-PHP יש כמה סוגי שגיאות
ברובם כבר נתקלנו, אם בקוד שלנו, אם באתרים אחרים.
[*] E_NOTICE
[*] E_ERROR
[*] E_WARNING
[*] E_DEPRECATED
[*] E_STRICT
[*] ...
שגיאות מסוימות הן קריטיות, שאחריהן הקוד מפסיק לפעול
אם בקוד שלכם קורה e_notice שלא טיפלתם בו (וחבל) - הקוד ימשיך לעבוד הלאה ולא יעצור.
שגיאות אחרות עשויות להעיף את כל הסקריפט קיבינימט ולהפסיק באמצע, לא משנה שבדיוק העברתם כסף מחשבון בנק אחד לחשבון בנק אחר.
בשגיאות הקריטיות מטפלים עם register_shutdown_function
והפעם למטרתנו נייעד את הפונקציה register_shutdown_function.
הפונקציה הנ"ל מאפשרת לנו לקחת כל פונקציה שנרצה ולהפעיל אותה אחרי שהסקריפט יסיים לפעול.
לדוגמה:
<?php
function the_last_function()
{
echo 'Last thing to happen,
after the entire script\'s execution is over';
}
register_shutdown_function('the_last_function');
echo 'blabla';
function the_last_function()
{
echo 'Last thing to happen,
after the entire script\'s execution is over';
}
register_shutdown_function('the_last_function');
echo 'blabla';
הפונקציה שלנו, the_last_function, תופעל רק אחרי שכל שאר הסקריפט יסיים לפעול.
היא תופעל גם אם הייתה שגיאה קריטית בסקריפט, מה שגרם לו לעצור באמצע:
<?php
function the_last_function()
{
echo '<br/>Last thing to happen,
after the entire script\'s execution is over';
}
register_shutdown_function('the_last_function');
echo 'Do something <br/>';
trigger_error('some error', E_USER_ERROR);
echo 'Script stopped. This will not be printed <br/>';
function the_last_function()
{
echo '<br/>Last thing to happen,
after the entire script\'s execution is over';
}
register_shutdown_function('the_last_function');
echo 'Do something <br/>';
trigger_error('some error', E_USER_ERROR);
echo 'Script stopped. This will not be printed <br/>';
שגיאה מסוג E_ERROR או E_USER_ERROR היא שגיאה קריטית (fatal error), מה שאומר שאחריה הסקריפט יפסיק לפעול. במקרה שלנו, ה-echo השני לא ידפיס שום דבר.
למזלנו, הפונקציה the_last_function בכל זאת הופעלה.
הפונקציה שלנו תופעל בכל פעם, גם אם לא הייתה שגיאה
עוד בעיה קטנה שעומדת בפנינו: גם אם בקוד לא הייתה אף שגיאה והוא עבד כמו שצריך, פונקציית ה-shutdown בכל זאת תופעל. מה אתם מציעים לעשות? לבדוק האם הייתה שגיאה?
נבדוק האם הייתה שגיאה בעזרת error_get_last
גם כאן PHP מצילה אותנו עם פונקציה מיוחדת, הפעם היא error_get_last, שמחזירה את המידע על השגיאה האחרונה שקרתה בסקריפט. אחד הדברים שהיא מוסרת, זה סוג השגיאה.
יכול מאוד להיות שבקוד היה לנו גם סתם notice שלא הוצג למסך בגלל @. (וקבלו טיפ: אל תשתמשו אף פעם ב-@.) במקרה זה לא הייתה לנו שגיאה קריטית כלשהי; error_get_last יחזיר אותה, אבל הסקריפט שלנו סיים לעבוד כמו שצריך ופלט למסך את מה שהוא היה צריך, בתבנית המתאימה והכל בסדר. לא צריך להרים מסוקים לאוויר אם זה כל מה שקרה.
בשביל לא להציג הודעות מפחידות סתם - נבדוק האם השגיאה קריטית
תנסו לבד או תמשיכו לקרוא:
<?php
function the_last_function()
{
static $haltCodes = array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR);
$error = error_get_last();
if ($error && in_array($error['type'], $haltCodes))
{
echo 'we had a fatal error';
}
else
{
echo 'either we had nor error, or no fatal error bumped';
}
}
register_shutdown_function('the_last_function');
echo 'Do something <br/>';
trigger_error('some error', E_USER_ERROR);
echo 'Script stopped. This will not be printed <br/>';
function the_last_function()
{
static $haltCodes = array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR);
$error = error_get_last();
if ($error && in_array($error['type'], $haltCodes))
{
echo 'we had a fatal error';
}
else
{
echo 'either we had nor error, or no fatal error bumped';
}
}
register_shutdown_function('the_last_function');
echo 'Do something <br/>';
trigger_error('some error', E_USER_ERROR);
echo 'Script stopped. This will not be printed <br/>';
לא צריך להסביר יותר מדי. יש רשימה של סוגי שגיאות קריטיות; אם נתקלנו באחת כזאת, אנחנו יודעים שהסקריפט שלנו עף באמצע וכדאי להציג הודעה מתאימה כלשהי.
שגיאה שנמצאת בתוך ה-shutdown function זה כבר מקרה אבוד
רצוי שבפונקציה שרושמים לסוף הסקריפט לא יקרו שגיאות; אותם כבר אין למי לטפוס.
משאר השגיאות אתם יכולים להרגיש מוגנים.
שימוש מעניין נוסף שראיתי לדבר הזה מעבר להודעות שגיאה היה מערכת שמורכבת ממודולים. כאשר אחד המודולים נתקל בשגיאה כלשהי, הגרעין של המערכת היה מפעיל את עצמו מחדש עם אותה בקשה אבל עם מודול כבוי, כך שהבקשה הייתה מתבצעת בכל זאת והחלק הלא פעיל נותק.
אתם תתנו לגולשים שלכם לשיר את שיר המתוסכלים ולעבור למתחרים אם חס וחלילה נפל המסד?
תגובות לכתבה:
מדריך מעולה, תודה :)
תודה רבה.
בפונקציה הייתי ממליץ לרשום E_RECOVERABLE_ERROR במקום 4096, יותר מובן.
לייק!
שוב תודה! :)
ו-iiddaannyy, תודה גם לך על ההסבר (לא הבנתי מה זה 4096). :)
שכחתי להוסיף: לפי מה שהבנתי מהדוקומניטציה, error_get_last מחזירה את פרטי השגיאה ממש כמו ב-set_error_handler, מה שאומר שיש לנו type, message, file ו-line, כך שאנחנו יכולים לעשות איתם מה שאנחנו רוצים, בין השאר לשלוח לעצמנו מייל עם הפרטים?
הבנת נכון :)
מה ה-static עושה שם ליד ה-$haltCodes?
מה שסטטיק עושה בכל פונקציה, קובע שהערך של המשתנה יהיה קבוע בכל הקריאות של הפונקציה .
למה, הוא יכול להשתנות?
משתנה לא סטטי משתנה בהחלט בכל פעם שאתה קורא לפונקציה .
קח את זה כדוגמא:
[php]function addToMyNum( $add )
{
$myNum = 0;
$myNum += intval($add);
return $myNum;
}
function addToMyStaticNum( $add )
{
static $myNum = 0;
$myNum += intval($add);
return $myNum;
}
echo addToMyNum(5); // 5
echo addToMyNum(5); // 5
echo addToMyStaticNum(5); // 5
echo addToMyStaticNum(5); // 10[/php]
לעומת זאת משתנה סטטי לא מתאתחל בכל פעם שתקרא לפונקציה .
אה, לא ידעתי. תודה. :)
פעלתי לפי המדריך הזה, ואני עדיין רואה שגיאות קריטיות על המסך (אם כי זה נוסף על כך שמה שכתבתי בפונקציה שלי התבצע גם). איך אני יכול להסתיר את השגיאות האלה?
return true בפונקציה שלך.
ניסיתי, לא עובד.
טעות שלי. אתה צודק לגמרי, זה בכל זאת יציג את השגיאה.
שמבחינתי זה מעולה. - תכתוב קוד בלי שגיאות :)
אם במקום מסוים אתה בכל זאת רוצה לאפשר ליצור שגיאות אבל לתפוס אותם במקום אחר - לרשותך עומד מנגנון ה exceptions.
אם אתה משתמש במנגנון הזה בצורה שאני ממליץ - בתור אופציה אחרונה בהחלט לתפוס קוד עם שגיאות שבכל זאת הגיע לפרודאקשן - תוכל לקמבן את האופציה הזו עם שימוש ב output buffering.
https://gist.github.com/3798792
כמובן שאני מנסה לכתוב קוד בלי שגיאות, אבל עדיין יכול להיות שיהיו. :)
מה שהצעת - זה מוחק גם את הודעת השגיאה של PHP, נכון?
זה מוחק את כל הפלט הקודם.
לא ניסית להפעיל את הקוד ?
אני לא יכול כרגע, ושכחתי שאפשר לעשות את זה גם פה.
בכל מקרה, הייתי צריך להבין את זה כבר, כי בניסיונות שלי ראיתי שהקוד שכתבתי בפונקציה הזאת בוצע אחרי הודעת השגיאה של PHP (מה שאומר שזה כן מוחק את זה).
תודה. :)
מה הבדל בין זה לset_error_handler? כי בסופו של דבר set_error_handler מזהה את הE_USER_ERROR ועוד כמה
ש set_error_handler לא מזהה שגיאות קריטיות אחרות, כמו פתאום נגמר הזיכרון, נתקעת ב timeout
או קיבלת וורנינג אחר.
ואיפו אפשר לברר מה כן מושפע?